package com.molichuxing.framework.utils;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.molichuxing.framework.property.StorageEnvEnum;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;

/**
 * 阿里云oss工具类
 * 
 * @author zoumingyu
 * @date 2019年8月25日
 *
 */
public final class OssUtil {
	private final static Logger logger = LoggerFactory.getLogger(OssUtil.class);

	// 设置URL过期时间为1小时3600*1000*1
	private static final long URL_DEFAULT_VALIDITY = 3600000L;

	// OSS的内或外网域名
	private static final String ENDPOINT = "oss-cn-hangzhou.aliyuncs.com";
	private static final String PUBLIC_ENDPOINT = "static-test.molichuxing.com";
	// OSS的密钥Access Key ID
	private static final String ACCESS_KEY_ID = "LTAI4RkCb2XN8l3X";
	// OSS的密钥Access Key Secret
	private static final String SECRET_ACCESS_KEY = "eQ6roVlpd7JSZ37mPmgQGiQ28yMO4A";

	private static ClientBuilderConfiguration CONFIG;

	private OssUtil() {
	}

	static {
		CONFIG = new ClientBuilderConfiguration();
		// 开启支持CNAME。CNAME是指将自定义域名绑定到存储空间上。
		CONFIG.setSupportCname(true);
		// 设置OSSClient允许打开的最大HTTP连接数，默认为1024个。
		CONFIG.setMaxConnections(200);
		// 设置Socket层传输数据的超时时间，默认为50000毫秒。
		CONFIG.setSocketTimeout(10000);
		// 设置建立连接的超时时间，默认为50000毫秒。
		CONFIG.setConnectionTimeout(10000);
		// 设置从连接池中获取连接的超时时间（单位：毫秒），默认不超时。
		CONFIG.setConnectionRequestTimeout(1000);
		// 设置连接空闲超时时间。超时则关闭连接，默认为60000毫秒。
		CONFIG.setIdleConnectionTime(10000);
		// 设置失败请求重试次数，默认为3次。
		CONFIG.setMaxErrorRetry(3);
		// 设置是否支持将自定义域名作为Endpoint，默认支持。
		CONFIG.setSupportCname(true);
		// 设置是否开启二级域名的访问方式，默认不开启。
		CONFIG.setSLDEnabled(false);
		// 设置连接OSS所使用的协议（HTTP/HTTPS），默认为HTTP。
		CONFIG.setProtocol(Protocol.HTTPS);
		// 设置用户代理，指HTTP的User-Agent头，默认为aliyun-sdk-java。
		CONFIG.setUserAgent("aliyun-sdk-java");
	}

	public static OSS getOSSClient() {
		return new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, SECRET_ACCESS_KEY, CONFIG);
	}

	public static OSS getOSSClient(StorageEnvEnum bucketEnv) {
		if (StorageEnvEnum.PRIVATE.equals(bucketEnv)) {
			return new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, SECRET_ACCESS_KEY, CONFIG);
		} else {

			return new OSSClientBuilder().build(PUBLIC_ENDPOINT, ACCESS_KEY_ID, SECRET_ACCESS_KEY, CONFIG);
		}
	}

	/**
	 * 创建模拟文件夹
	 *
	 * @param bucketName 存储空间
	 * @param folder     模拟文件夹名如"c-contract/"
	 * @return 文件夹名
	 */
	public static String createFolder(String bucketName, String folder) {
		return createFolder(getOSSClient(), bucketName, folder);
	}

	/**
	 * 创建模拟文件夹
	 *
	 * @param ossClient  oss连接
	 * @param bucketName 存储空间
	 * @param folder     模拟文件夹名如"c-contract/"
	 * @return 文件夹名
	 */
	public static String createFolder(OSS ossClient, String bucketName, String folder) {
		// 文件夹名
		final String keySuffixWithSlash = folder;
		// 判断文件夹是否存在，不存在则创建
		if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
			// 创建文件夹
			ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
			logger.info("创建文件夹成功");
			// 得到文件夹名
			OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
			String fileDir = object.getKey();
			return fileDir;
		}
		return keySuffixWithSlash;
	}

	/**
	 * 上传文件至oss
	 *
	 * @param bucketName bucketName
	 * @param is         InputStream输入流
	 * @param folderPath oss文件夹路径
	 * @param fileName   文件名
	 * @param bucketEnv  bucket环境
	 * @param prefixUrl  需要替换的前缀
	 * @return
	 */
	public static String uploadFile(String bucketName, InputStream is, String folderPath, String fileName,
	                                StorageEnvEnum bucketEnv, String prefixUrl) {
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, folderPath + "/" + fileName, is);
		return uploadFile(putObjectRequest, bucketEnv, prefixUrl);
	}

	/**
	 * 上传文件至oss
	 *
	 * @param bucketName bucketName
	 * @param file       文件File
	 * @param folderPath oss文件夹路径
	 * @param fileName   文件名
	 * @param bucketEnv  bucket环境
	 * @return
	 */
	public static String uploadFile(String bucketName, File file, String folderPath, String fileName,
	                                StorageEnvEnum bucketEnv, String prefixUrl) {
		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, folderPath + "/" + fileName, file);
		return uploadFile(putObjectRequest, bucketEnv, prefixUrl);
	}

	/**
	 * 上传文件至oss(txt中文内容会乱码，暂未解决)
	 *
	 * @param putObjectRequest
	 *            putObjectRequest
	 * @param bucketEnv
	 *            bucket环境
	 * @return
	 */
	public static String uploadFile(PutObjectRequest putObjectRequest, StorageEnvEnum bucketEnv, String prefixUrl) {
		String resultUrl = null;
		OSS ossClient = null;
		try {
			// 创建上传Object的Metadata
			ObjectMetadata metadata = new ObjectMetadata();
			// 指定该Object被下载时的网页的缓存行为
			metadata.setCacheControl("no-cache");
			// 指定该Object下设置Header
			metadata.setHeader("Pragma", "no-cache");
			// 指定该Object被下载时的内容编码格式
			metadata.setContentEncoding("UTF-8");
			// 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
			metadata.setContentType(
					getContentType(putObjectRequest.getKey().substring(putObjectRequest.getKey().lastIndexOf("."))));
			putObjectRequest.setMetadata(metadata);
			// 获取ossClient
			ossClient = getOSSClient(bucketEnv);
			// 上传
			ossClient.putObject(putObjectRequest);
			// 获取url链接
			if (StorageEnvEnum.PRIVATE.equals(bucketEnv)) {
				// 私有
				resultUrl = getUrl(ossClient, putObjectRequest.getBucketName(), putObjectRequest.getKey());

				if (StringUtils.isNotBlank(prefixUrl)) {
//					resultUrl = resultUrl.replace(putObjectRequest.getBucketName() + "." + ENDPOINT, prefixUrl);
					resultUrl = resultUrl.replace(ENDPOINT, prefixUrl);
				}
			} else {
				if (StringUtils.isNotBlank(prefixUrl)) {
					resultUrl = "https://" + prefixUrl + putObjectRequest.getKey();
				} else {
//					resultUrl = "https://" + putObjectRequest.getBucketName() + "." + ENDPOINT + "/"
//							+ putObjectRequest.getKey();
					resultUrl = "https://" + PUBLIC_ENDPOINT + "/" + putObjectRequest.getKey();
				}
			}
		} finally {
			if (ossClient != null) {
				ossClient.shutdown();
			}
		}
		return resultUrl;
	}

	/**
	 * 下载文件到本地
	 *
	 * @param bucketName bucketName
	 * @param file       本地文件存储路径（文件夹必须存在）
	 * @param folderPath oss文件夹路径
	 * @param fileName   文件名
	 */
	public static void download(String bucketName, File file, String folderPath, String fileName) {
		OSS ossClient = getOSSClient();
		ossClient.getObject(new GetObjectRequest(bucketName, folderPath + "/" + fileName), file);
	}

	/**
	 * 获取url链接(默认有效期1小时)
	 * 
	 * @param bucketName
	 *            bucketName
	 * @param fileName
	 *            文件名
	 * @return
	 */
	public static String getUrl(String bucketName, String fileName) {
		// 设置URL过期时间为
		Date expiration = new Date(new Date().getTime() + URL_DEFAULT_VALIDITY);
		return getUrl(bucketName, fileName, expiration);
	}

	/**
	 * 获取url链接
	 * 
	 * @param bucketName
	 *            bucketName
	 * @param fileName
	 *            文件名
	 * @param expiration
	 *            链接过期时间
	 * @return
	 */
	public static String getUrl(String bucketName, String fileName, Date expiration) {
		return getUrl(getOSSClient(), bucketName, fileName, expiration);
	}

	/**
	 * 获取url链接(默认有效期1小时)
	 * 
	 * @param ossClient
	 *            ossClient
	 * @param bucketName
	 *            bucketName
	 * @param fileName
	 *            文件名
	 * @return
	 */
	public static String getUrl(OSS ossClient, String bucketName, String fileName) {
		Date expiration = new Date(new Date().getTime() + URL_DEFAULT_VALIDITY);
		return getUrl(ossClient, bucketName, fileName, expiration);
	}

	/**
	 * 获取url链接
	 * 
	 * @param ossClient
	 *            ossClient
	 * @param bucketName
	 *            bucketName
	 * @param fileName
	 *            文件名
	 * @param expiration
	 *            链接过期时间
	 * @return
	 */
	public static String getUrl(OSS ossClient, String bucketName, String fileName, Date expiration) {
		// 生成URL
		URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);
		if (url == null) {
			return null;
		}
		return url.toString();
	}

	/**
	 * 根据key删除OSS服务器上的文件
	 *
	 * @param bucketName
	 *            存储空间
	 * @param folder
	 *            模拟文件夹名 如"molichuxing/"
	 * @param key
	 *            Bucket下的文件的路径名+文件名 如："upload/cake.jpg"
	 */
	public static void deleteFile(String bucketName, String folder, String key) {
		OSS ossClient = getOSSClient();
		ossClient.deleteObject(bucketName, folder + key);
		logger.info("删除" + bucketName + "下的文件" + folder + key + "成功");
	}

	/**
	 * 通过文件名判断并获取OSS服务文件上传时文件的contentType
	 *
	 * @param suffix 文件后缀
	 * @return
	 */
	public static String getContentType(String suffix) {
		if (".bmp".equalsIgnoreCase(suffix)) {
			return "image/bmp";
		}
		if (".gif".equalsIgnoreCase(suffix)) {
			return "image/gif";
		}
		if (".jpeg".equalsIgnoreCase(suffix) || ".jpg".equalsIgnoreCase(suffix) || ".png".equalsIgnoreCase(suffix)) {
			return "image/jpeg";
		}
		if (".html".equalsIgnoreCase(suffix)) {
			return "text/html";
		}
		if (".txt".equalsIgnoreCase(suffix)) {
			return "text/plain";
		}
		if (".vsd".equalsIgnoreCase(suffix)) {
			return "application/vnd.visio";
		}
		if (".ppt".equalsIgnoreCase(suffix) || "pptx".equalsIgnoreCase(suffix)) {
			return "application/vnd.ms-powerpoint";
		}
		if (".doc".equalsIgnoreCase(suffix) || "docx".equalsIgnoreCase(suffix)) {
			return "application/msword";
		}
		if (".xml".equalsIgnoreCase(suffix)) {
			return "text/xml";
		}
		if (".pdf".equalsIgnoreCase(suffix)) {
			return "application/pdf";
		}
		// 默认返回类型
		return "image/jpeg";
	}

//	public static void main(String[] args) throws FileNotFoundException,
//			IOException {
//		String path = "D:/tmp/基础数据.txt";
//		InputStream is = new FileInputStream(path);
//
//		String md5 = DigestUtils.md5Hex(is);
//		System.out.println(md5);
//		// cc25ebee3c3ace044f8c0b74d2f2fa51
//
//		File file = new File(path);
//
//		System.out.println(OssUtil.uploadFile("moliv2dev", file, "test3", md5
//				+ ".txt", StorageEnvEnum.PUBLIC, null));
//
////		OssUtil.download("moliv2private", new File("D:/tmp/download/test3/" + md5
////				+ ".txt"), "test3", md5 + ".txt");
//	}

//	public static void main(String[] args) {
//		String bucketName = "moliv2dev";
//		File file = new File("\\file_data\\public\\check\\2020\\0811\\bea50736ed3e3f3a.png");
//		String folderPath = "check/2020/0811";
//		String fileName = "bea50736ed3e3f3a.png";
//		if (!file.getParentFile().exists()) {
//			file.getParentFile().mkdirs();
//		}
//
//		download(bucketName, file, folderPath, fileName);
//	}

}
